/*
 * Copyright (C) Francisco Morero Peyrona. All rights reserved.
 *
 * This software is published under the terms of Open Source
 * License version 1.1, a copy of which has been included with this
 * distribution in the License.txt file.
 */

package jdbcmanager.awt;

import java.awt.*;

import javax.swing.SwingConstants;

/*
 * NOTE: I found this code in: http://www.archive.cc.yamaguchi-u.ac.jp/apl/talib/
 * <p>
 * I could not find any copyright or license note.<br>
 * Please, if someone knows about it, just let me know.<br>
 * I made minimum changes in the code.
 */

/**
 * A vertical flow layout arranges components in a top-to-bottom flow, much
 * like lines of text in a paragraph. Flow layouts are typically used
 * to arrange buttons in a panel. It will arrange
 * buttons top to bottom until no more buttons fit on the same line.
 * Each line is centered.
 * <p>
 * For example, the following picture shows an applet using the vertical flow
 * layout manager to position three buttons:
 * <p>
 * <img src="images-awt/VerticalFlowLayout-1.png"
 * ALT="Graphic of Layout for Three Buttons"
 * ALIGN=center HSPACE=10 VSPACE=7>
 * <p>
 * Here is the code for this applet:
 * <p>
 * <hr><blockquote><pre>
 * import java.awt.*;
 * import java.applet.Applet;
 * import ta.awt.*;
 *
 * public class myButtons extends Applet {
 *     Button button1, button2, button3;
 *     public void init() {
 *         setLayout(new VerticalFlowLayout());
 *         button1 = new Button("Ok");
 *         button2 = new Button("Open");
 *         button3 = new Button("Close");
 *         add(button1);
 *         add(button2);
 *         add(button3);
 *     }
 * }
 * </pre></blockquote><hr>
 * <p>
 * A vertical flow layout lets each component assume its natural (preferred) size.
 *
 * @version 	1.0, Thu Apr 29 13:39:30 1999
 * @author 	Toshimizu Abiko
 * @since       JDK1.0
 */
public class VerticalFlowLayout implements LayoutManager, java.io.Serializable
{
   int align;
   int subAlign;
   int hgap;
   int vgap;

   /*
    * JDK 1.1 serialVersionUID
    */
   //private static final long serialVersionUID = -7262534875583282631L;

   /**
    * Constructs a new Vertical Flow Layout with a centered alignment and a
    * default 5-unit horizontal and vertical gap,
    * and a centered sub-alignment.
    * @since JDK1.0
    */
   public VerticalFlowLayout()
   {
      this( SwingConstants.CENTER, 5, 5, SwingConstants.CENTER );
   }

   /**
    * Constructs a new Vertical Flow Layout with the specified alignment and a
    * default 5-unit horizontal and vertical gap,
    * and a centered sub-alignment.
    * <p>
    * The value of the alignment argument must be one of
    * <code>VerticalFlowLayout.TOP</code>, <code>VerticalFlowLayout.BOTTOM</code>,
    * or <code>VerticalFlowLayout.CENTER</code>.
    * @param align the alignment value
    * @since JDK1.0
    */
   public VerticalFlowLayout( int align )
   {
      this( align, 5, 5, SwingConstants.CENTER );
   }

   /**
    * Creates a new vertical flow layout manager with the indicated alignment
    * and the indicated horizontal and vertical gaps,
    * and a centered sub-alignment.
    * <p>
    * The value of the alignment argument must be one of
    * <code>VerticalFlowLayout.TOP</code>, <code>VerticalFlowLayout.BOTTOM</code>,
    * or <code>VerticalFlowLayout.CENTER</code>.
    * @param      align   the alignment value.
    * @param      hgap    the horizontal gap between components.
    * @param      vgap    the vertical gap between components.
    * @since      JDK1.0
    */
   public VerticalFlowLayout( int align, int hgap, int vgap )
   {
      this( align, hgap, vgap, SwingConstants.CENTER );
   }

   /**
    * Creates a new vertical flow layout manager with the indicated alignment
    * and the indicated horizontal and vertical gaps
    * and the indicated sub-alignment.
    * <p>
    * The value of the alignment argument must be one of
    * <code>VerticalFlowLayout.TOP</code>, <code>VerticalFlowLayout.BOTTOM</code>,
    * or <code>VerticalFlowLayout.CENTER</code>.
    * <p>
    * The value of the sub-alignment argument must be one of
    * <code>VerticalFlowLayout.LEFT</code>, <code>VerticalFlowLayout.RIGHT</code>,
    * or <code>VerticalFlowLayout.CENTER</code>.
    *
    * @param      align   the alignment value.
    * @param      hgap    the horizontal gap between components.
    * @param      vgap    the vertical gap between components.
    * @param      subAlign   the sub-alignment value.
    * @since      JDK1.0
    */
   public VerticalFlowLayout( int align, int hgap, int vgap, int subAlign )
   {
      this.align = align;
      this.hgap = hgap;
      this.vgap = vgap;
      this.subAlign = subAlign;
   }

   /**
    * Gets the alignment for this layout.
    * Possible values are <code>VerticalFlowLayout.TOP</code>,
    * <code>VerticalFlowLayout.CENTER</code>, or <code>VerticalFlowLayout.BOTTOM</code>.
    * @return     the alignment value for this layout.
    * @see        ta.awt.VerticalFlowLayout#setAlignment
    * @since      JDK1.1
    */
   public int getAlignment()
   {
      return align;
   }

   /**
    * Sets the alignment for this layout.
    * Possible values are <code>VerticalFlowLayout.TOP</code>,
    * <code>VerticalFlowLayout.CENTER</code>, and <code>VerticalFlowLayout.BOTTOM</code>.
    * @param      align the alignment value.
    * @see        ta.awt.VerticalFlowLayout#getAlignment
    * @since      JDK1.1
    */
   public void setAlignment( int align )
   {
      this.align = align;
   }

   /**
    * Gets the sub-alignment for this layout.
    * Possible values are <code>VerticalFlowLayout.LEFT</code>,
    * <code>VerticalFlowLayout.RIGHT</code>, or <code>VerticalFlowLayout.CENTER</code>.
    * @return     the sub-alignment value for this layout.
    * @see        ta.awt.VerticalFlowLayout#setSubAlignment
    * @since      JDK1.1
    */
   public int getSubAlignment()
   {
      return subAlign;
   }

   /**
    * Sets the sub-alignment for this layout.
    * Possible values are <code>VerticalFlowLayout.LEFT</code>,
    * <code>VerticalFlowLayout.RIGHT</code>, and <code>VerticalFlowLayout.CENTER</code>.
    * @param      subAlign the sub-alignment value.
    * @see        ta.awt.VerticalFlowLayout#getSubAlignment
    * @since      JDK1.1
    */
   public void setSubAlignment( int subAlign )
   {
      this.subAlign = subAlign;
   }

   /**
    * Gets the horizontal gap between components.
    * @return     the horizontal gap between components.
    * @see        ta.awt.VerticalFlowLayout#setHgap
    * @since      JDK1.1
    */
   public int getHgap()
   {
      return hgap;
   }

   /**
    * Sets the horizontal gap between components.
    * @param hgap the horizontal gap between components
    * @see        ta.awt.VerticalFlowLayout#getHgap
    * @since      JDK1.1
    */
   public void setHgap( int hgap )
   {
      this.hgap = hgap;
   }

   /**
    * Gets the vertical gap between components.
    * @return     the vertical gap between components.
    * @see        ta.awt.VerticalFlowLayout#setVgap
    * @since      JDK1.1
    */
   public int getVgap()
   {
      return vgap;
   }

   /**
    * Sets the vertical gap between components.
    * @param vgap the vertical gap between components
    * @see        ta.awt.VerticalFlowLayout#getVgap
    * @since      JDK1.1
    */
   public void setVgap( int vgap )
   {
      this.vgap = vgap;
   }

   /**
    * Adds the specified component to the layout. Not used by this class.
    * @param name the name of the component
    * @param comp the component to be added
    * @since JDK1.0
    */
   public void addLayoutComponent( String name, Component comp )
   {
   }

   /**
    * Removes the specified component from the layout. Not used by
    * this class.
    * @param comp the component to remove
    * @see       java.awt.Container#removeAll
    * @since     JDK1.0
    */
   public void removeLayoutComponent( Component comp )
   {
   }

   /**
    * Returns the preferred dimensions for this layout given the components
    * in the specified target container.
    * @param target the component which needs to be laid out
    * @return    the preferred dimensions to lay out the
    *                    subcomponents of the specified container.
    * @see Container
    * @see #minimumLayoutSize
    * @see       java.awt.Container#getPreferredSize
    * @since     JDK1.0
    */
   public Dimension preferredLayoutSize( Container target )
   {
      synchronized( target.getTreeLock() )
      {
         Dimension dim = new Dimension( 0, 0 );
         int nmembers = target.getComponentCount();

         for( int i = 0; i < nmembers; i++ )
         {
            Component m = target.getComponent( i );
            if( m.isVisible() )
            {
               Dimension d = m.getPreferredSize();
               dim.width = Math.max( dim.width, d.width );
               if( i > 0 )
               {
                  dim.height += vgap;
               }
               dim.height += d.height;
            }
         }
         Insets insets = target.getInsets();
         dim.height += insets.top + insets.bottom + vgap * 2;
         dim.width += insets.left + insets.right + hgap * 2;
         return dim;
      }
   }

   /**
    * Returns the minimum dimensions needed to layout the components
    * contained in the specified target container.
    * @param target the component which needs to be laid out
    * @return    the minimum dimensions to lay out the
    *                    subcomponents of the specified container.
    * @see #preferredLayoutSize
    * @see       java.awt.Container
    * @see       java.awt.Container#doLayout
    * @since     JDK1.0
    */
   public Dimension minimumLayoutSize( Container target )
   {
      synchronized( target.getTreeLock() )
      {
         Dimension dim = new Dimension( 0, 0 );
         int nmembers = target.getComponentCount();

         for( int i = 0; i < nmembers; i++ )
         {
            Component m = target.getComponent( i );
            if( m.isVisible() )
            {
               Dimension d = m.getMinimumSize();
               dim.width = Math.max( dim.width, d.width );
               if( i > 0 )
               {
                  dim.height += vgap;
               }
               dim.height += d.height;
            }
         }
         Insets insets = target.getInsets();
         dim.height += insets.top + insets.bottom + vgap * 2;
         dim.width += insets.left + insets.right + hgap * 2;
         return dim;
      }
   }

   /**
    * Centers the elements in the specified row, if there is any slack.
    * @param target the component which needs to be moved
    * @param x the x coordinate
    * @param y the y coordinate
    * @param width the width dimensions
    * @param height the height dimensions
    * @param rowStart the beginning of the row
    * @param rowEnd the the ending of the row
    */
   private void moveComponents( Container target, int x, int y, int width, int height, int columnStart, int columnEnd )
   {
      synchronized( target.getTreeLock() )
      {
         switch( align )
         {
            case SwingConstants.TOP:
               break;
            case SwingConstants.CENTER:
               y += height / 2;
               break;
            case SwingConstants.BOTTOM:
               y += height;
               break;
         }
         for( int i = columnStart; i < columnEnd; i++ )
         {
            Component m = target.getComponent( i );
            if( m.isVisible() )
            {
               int dx;
               switch( subAlign )
               {
                  case SwingConstants.CENTER:
                     dx = ( width - m.getSize().width ) / 2;
                     break;
                  case SwingConstants.LEFT:
                     dx = 0;
                     break;
                  case SwingConstants.RIGHT:
                     dx = width - m.getSize().width;
                     break;
                  default:
                     throw new IllegalStateException( "subAlign = " + subAlign );
               }
               m.setLocation( x + dx, y );
               y += vgap + m.getSize().height;
            }
         }
      }
   }

   /**
    * Lays out the container. This method lets each component take
    * its preferred size by reshaping the components in the
    * target container in order to satisfy the constraints of
    * this <code>VerticalFlowLayout</code> object.
    * @param target the specified component being laid out.
    * @see Container
    * @see       java.awt.Container#doLayout
    * @since     JDK1.0
    */
   public void layoutContainer( Container target )
   {
      synchronized( target.getTreeLock() )
      {
         Insets insets = target.getInsets();
         int maxheight = target.getSize().height - ( insets.top + insets.bottom + vgap * 2 );
         int nmembers = target.getComponentCount();
         int y = 0, x = insets.left + hgap;
         int columnw = 0, start = 0;

         for( int i = 0; i < nmembers; i++ )
         {
            Component m = target.getComponent( i );
            if( m.isVisible() )
            {
               Dimension d = m.getPreferredSize();
               m.setSize( d.width, d.height );

               if( ( y == 0 ) || ( ( y + d.height ) <= maxheight ) )
               {
                  if( y > 0 )
                  {
                     y += vgap;
                  }
                  y += d.height;
                  columnw = Math.max( columnw, d.width );
               }
               else
               {
                  moveComponents( target, x, insets.top + vgap, columnw, maxheight - y, start, i );
                  y = d.height;
                  x += hgap + columnw;
                  columnw = d.width;
                  start = i;
               }
            }
         }
         moveComponents( target, x, insets.top + vgap, columnw, maxheight - y, start, nmembers );
      }
   }

   /**
    * Returns a string representation of this <code>VerticalFlowLayout</code>
    * object and its values.
    * @return     a string representation of this layout.
    * @since      JDK1.0
    */
   public String toString()
   {
      String str = "";
      switch( align )
      {
         case SwingConstants.TOP:
            str = ",align=top";
            break;
         case SwingConstants.CENTER:
            str = ",align=center";
            break;
         case SwingConstants.BOTTOM:
            str = ",align=bottom";
            break;
      }
     String subStr = "";
      switch( subAlign )
      {
         case SwingConstants.LEFT:
            subStr = ",subAlign=left";
            break;
         case SwingConstants.CENTER:
            subStr = ",subAlign=center";
            break;
         case SwingConstants.RIGHT:
            subStr = ",subAlign=right";
            break;
      }
      return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + str + subStr + "]";
   }
}